#include "ModbusDevice.h"

ModbusDevice::ModbusDevice(QObject *parent) :
    BaseInterface<ModbusDevice>(parent)
{
    m_pInstance = this;
    modbusProtocol = new ModbusProtocol(this);
    pointProtocol = new PointProtocol(this);
    this->registerProtocol(pointProtocol);
    this->registerProtocol(modbusProtocol);

    currentModbusCmd = NULL;
    m_isWaiting = 0;

    m_cmdMap.insert(ReadCoilRegisterCmd::FunctionCode,ReadCoilRegisterCmd::staticMetaObject);
    m_cmdMap.insert(ReadDiscreteCoilRegisterCmd::FunctionCode,ReadDiscreteCoilRegisterCmd::staticMetaObject);
    m_cmdMap.insert(ReadHoldRegisterCmd::FunctionCode,ReadHoldRegisterCmd::staticMetaObject);
    m_cmdMap.insert(ReadInputRegisterCmd::FunctionCode,ReadInputRegisterCmd::staticMetaObject);
    m_cmdMap.insert(WriteSignalCoilRegisterCmd::FunctionCode,WriteSignalCoilRegisterCmd::staticMetaObject);
    m_cmdMap.insert(WriteSignalHoldRegisterCmd::FunctionCode,WriteSignalHoldRegisterCmd::staticMetaObject);
    m_cmdMap.insert(WriteMultCoilRegisterCmd::FunctionCode,WriteMultCoilRegisterCmd::staticMetaObject);
    m_cmdMap.insert(WriteMultHoldRegisterCmd::FunctionCode,WriteMultHoldRegisterCmd::staticMetaObject);

    registerCmdHandler(ReadCoilRegisterCmd::FunctionCode,ReadCoilRegisterCmd::staticMetaObject, &ModbusDevice::readCoilRegisterCmdHandle);
    registerCmdHandler(ReadDiscreteCoilRegisterCmd::FunctionCode,ReadDiscreteCoilRegisterCmd::staticMetaObject, &ModbusDevice::readDiscreteCoilRegisterCmdHandle);
    registerCmdHandler(ReadHoldRegisterCmd::FunctionCode,ReadHoldRegisterCmd::staticMetaObject, &ModbusDevice::readHoldRegisterCmdHandle);
    registerCmdHandler(ReadInputRegisterCmd::FunctionCode,ReadInputRegisterCmd::staticMetaObject, &ModbusDevice::readInputRegisterCmdHandle);

    registerCmdHandler(WriteSignalCoilRegisterCmd::FunctionCode,WriteSignalCoilRegisterCmd::staticMetaObject, &ModbusDevice::writeSignalCoilRegisterCmdHandle);
    registerCmdHandler(WriteSignalHoldRegisterCmd::FunctionCode,WriteSignalHoldRegisterCmd::staticMetaObject, &ModbusDevice::writeSignalHoldRegisterCmdHandle);
    registerCmdHandler(WriteMultCoilRegisterCmd::FunctionCode,WriteMultCoilRegisterCmd::staticMetaObject, &ModbusDevice::writeMultCoilRegisterCmdHandle);
    registerCmdHandler(WriteMultHoldRegisterCmd::FunctionCode,WriteMultHoldRegisterCmd::staticMetaObject, &ModbusDevice::writeMultHoldRegisterCmdHandle);

    registerCmdTimeOUTHandler(ReadCoilRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(ReadDiscreteCoilRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(ReadHoldRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(ReadInputRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(WriteSignalCoilRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(WriteSignalHoldRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(WriteMultCoilRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);
    registerCmdTimeOUTHandler(WriteMultHoldRegisterCmd::FunctionCode,&ModbusDevice::modbusCmdTimeoutHandle);

    registerFuncHandler(ControlPointFunc::FunctionCode, &ModbusDevice::controlPointFuncHandle);

    registerFuncHandler(SendQueryData::FunctionCode, &ModbusDevice::sendQueryData);
}

void ModbusDevice::sendCmdQueue()
{
    if(!m_isWaiting)
    {
        if(!m_sendCmdQueue.isEmpty())
        {
            PortStruct target;
            foreach (const BasePort *port , m_portList)
            {
                 if((port->portParam().type() == "UART" && port->portParam().name() == "RS485"))
                 {
                     target = port->portParam();
                 }
            }
            QSharedPointer<BaseCmd> sharedModbusCmd = m_sendCmdQueue.dequeue();
            currentModbusCmd = (BaseModbusCmd*)sharedModbusCmd.data();
            sendCmd(target,sharedModbusCmd);
            m_isWaiting = true;
        }
        else
        {
            currentModbusCmd = NULL;
        }
    }
}

void ModbusDevice::readCoilRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::readDiscreteCoilRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::readHoldRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
   PointProtocol a;
   qDebug()<<"modbus order =0x03----------";
    ModbusListXml *modbusListXml = ModbusListXml::getInstance();

    LogicController *logicController = new LogicController(this);
    ModbusControlStruct Struct;
    qDebug()<<modbusListXml->m_queryNum;
    if(modbusListXml->m_queryNum>0)
    {
       Struct=modbusListXml->m_modbusQueryMap.value(modbusListXml->m_queryNo);
       qDebug()<<Struct.pointAddress();
    }
    ReadHoldRegisterCmd *readHoldRegisterCmd = qobject_cast<ReadHoldRegisterCmd*>(sharedCmd.data());
    ModbusControlStruct modbusControl = readHoldRegisterCmd->modbusControl();
    QList<quint16>modbusList=modbusControl.registrValueList();
    foreach(const quint16 registrValue,modbusList)
    {
        const quint16 datavalue=logicController->calculationData(Struct.calculationMode(),registrValue);
        qDebug()<<datavalue;
        qDebug()<<"this data pointaddr="<<Struct.pointAddress()<<" Value="<<datavalue;
        quint16 function=0x0f80;
        QByteArray data = a.getPointData(function,Struct.pointAddress(),datavalue);
        modbusListXml->m_queryStata=0;
        sendDataSignal(source,data);
    }
}

void ModbusDevice::readInputRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
   qDebug()<<"modbus order =0x04-------1---";
    ReadInputRegisterCmd *readInputRegisterCmd = qobject_cast<ReadInputRegisterCmd*>(sharedCmd.data());

    if(currentModbusCmd != NULL)
    {
        qDebug()<<"modbus order =0x04----2------";
        if(currentModbusCmd->functionCode() == readInputRegisterCmd->functionCode())
        {
            qDebug()<<"modbus order =0x04----3------";
            ModbusControlStruct modbusControl = readInputRegisterCmd->modbusControl();
            quint8 registerStartAddress = currentModbusCmd->modbusControl().registerStartAddress();
            modbusControl.setRegisterStartAddress(registerStartAddress);

            ModbusListXml *modbusListXml = ModbusListXml::getInstance();
            QList<ControlPointStruct> sourcePointList = modbusListXml->controlPointList(modbusControl);
            if(!sourcePointList.isEmpty())
            {
                qDebug()<<"modbus order =0x04----4------";
                ControlPointFunc *pointControlFunc = new ControlPointFunc();
                pointControlFunc->setSourceDevice(this->name());
                pointControlFunc->setSourcePointList(sourcePointList);

                QSharedPointer<BaseFunc> sharedPointControlFunc(pointControlFunc);
                emit transferFuncSignal(sharedPointControlFunc);
            }
            m_isWaiting = false;
            sendCmdQueue();
        }
    }

}

void ModbusDevice::writeSignalCoilRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::writeSignalHoldRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::writeMultCoilRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::writeMultHoldRegisterCmdHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    if(currentModbusCmd != NULL)
    {
        if(currentModbusCmd->functionCode() == sharedCmd->functionCode())
        {
            m_isWaiting = false;
            sendCmdQueue();
        }
    }
}

void ModbusDevice::modbusCmdTimeoutHandle(PortStruct source, QSharedPointer<BaseCmd> sharedCmd)
{
    Q_UNUSED(source);
    Q_UNUSED(sharedCmd);
    qDebug()<<"ModbusCmd timeout handle!!!";
    m_isWaiting = false;
    sendCmdQueue();

}

void ModbusDevice::controlPointFuncHandle(QSharedPointer<BaseFunc> sharedFunc)
{
    qDebug()<<"hello";
    ControlPointFunc *pointControlFunc = qobject_cast<ControlPointFunc*>(sharedFunc.data());

    QList<ControlPointStruct> controlPointList;
    controlPointList.append(pointControlFunc->sourcePointList());
    controlPointList.append(pointControlFunc->controlPointList());
    if(controlPointList.isEmpty())
    {
        return;
    }

    ModbusListXml *modbusListXml = ModbusListXml::getInstance();
    QList<ModbusControlStruct> modbusControlList = modbusListXml->modbusControlList(controlPointList);

    PortStruct target;
    foreach (const BasePort *port , m_portList)
    {
         if((port->portParam().type() == "UART" && port->portParam().name() == "RS485"))
         {
             target = port->portParam();
         }
    }

    foreach (const ModbusControlStruct &modbusControl, modbusControlList)
    {

        quint8 functionCode = modbusControl.functionCode();
        if(!m_cmdMap.contains(functionCode))
        {
            continue;
        }
        QMetaObject meta = m_cmdMap.value(functionCode);

        BaseModbusCmd *pCmd = static_cast<BaseModbusCmd*>(meta.newInstance());
        pCmd->setModbusControl(modbusControl);
        quint16 cmdId = ((quint16)modbusControl.deviceAddress() << 8) | modbusControl.functionCode();
        pCmd->setCmdId(cmdId);
        QSharedPointer<BaseCmd> sharedModbusCmd((BaseCmd*)pCmd);
        m_sendCmdQueue.enqueue(sharedModbusCmd);
        sendCmdQueue();
    }
}

void ModbusDevice::sendQueryData(QSharedPointer<BaseFunc> sharedFunc)
{
    SendQueryData *sendQuery = qobject_cast<SendQueryData*>(sharedFunc.data());

    QByteArray data=sendQuery->getData();
    PortStruct target;
    foreach (const BasePort *port , m_portList)
    {
         if((port->portParam().type() == "UART" && port->portParam().name() == "RS485"))
         {
             target = port->portParam();
         }
    }
    sendDataSignal(target,data);
}
